#pragma once

#include "MyTimer.h"
#include "Logger.h"

#include <vector>

#include <boost/shared_ptr.hpp>

class Test
{
	std::string s;
public:
	typedef boost::shared_ptr<Test> SharedPtr;

	Test(std::string _s):s(_s){};
	virtual ~Test(){};
	virtual void run()=0;
	virtual std::string getName(){return s;};
};


#include "OpenClTemplate.h"

namespace Tests
{

	class Example: public Test
	{
	public:
		Example():Test("TestExample"){};

		void run()
		{
			OpenClTemplate::exampleUse();
		}
	};


	class ExampleCPU: public Test
	{
	public:
		ExampleCPU():Test("ExampleCPU"){};

		void run()
		{
			OpenClTemplate::exampleUseCPU();
		}
	};

}// namespace Tests


#include "KMeansStandardV1NonConcurrent.h"


namespace Tests
{

namespace KMeansStandardV1NonConcurrent
{

	class TmpTest1: public Test
	{
	public:
		typedef Algorithm::KMeansStandardV1NonConcurrent<10,100,10> TAlgorithm;
		TAlgorithm::SupportedKMeansStandardV1_Util::TSpAlgorithmData algorithmData;

		TmpTest1():Test("KMeansStandardV1NonConcurrentTest::TmpTest1")
		{
			algorithmData=TAlgorithm::SupportedKMeansStandardV1_Util::GenerateAlgorithmDataRandom::generate();
		};

		void run()
		{
			TAlgorithm::algorithm(algorithmData);
		}
	};
};

}// namespace Tests

#include "KMeansStandardV1ConcurrentV1.h"

namespace Tests
{

namespace KMeansStandardV1ConcurrentV1
{

	class TmpTest1: public Test
	{
	public:
		typedef Algorithm::KMeansStandardV1ConcurrentV1<1,10,1> TAlgorithm;
		typedef Algorithm::KMeansStandardV1NonConcurrent<1,10,1> TAlgorithmDebuging;

		TAlgorithm::SupportedKMeansStandardV1_Util::TSpAlgorithmData algorithmData;
		TAlgorithmDebuging::SupportedKMeansStandardV1_Util::TSpAlgorithmData algorithmDataDebuging;


		TmpTest1():Test("KMeansStandardV1ConcurrentV1Test::TmpTest1")
		{

			algorithmData=TAlgorithm::SupportedKMeansStandardV1_Util::GenerateAlgorithmDataRandom::generate();

			Logger::TurnOffLogger turnOffLogger;

			algorithmDataDebuging.reset(new TAlgorithm::SupportedKMeansStandardV1_Util::TAlgorithmData);
			*algorithmDataDebuging=*algorithmData;
			TAlgorithmDebuging::algorithm(algorithmDataDebuging);
		};

		void run()
		{
			TAlgorithm::algorithm(algorithmData);

			if(!(algorithmData->currentCentroids==algorithmDataDebuging->currentCentroids))
				throw GlobalException("Invalid output");

		}
	};
};

}// namespace Tests


#include "KMeansStandardV1ConcurrentV2.h"


//_____________________________________________________________________________
//COMPARISON TESTS
//_____________________________________________________________________________

namespace Tests
{

template<class __GenerateAlgorithmData,unsigned int OBSERVATION_VECTOR_SIZE, unsigned int NUMBER_OF_OBSERVATIONS, unsigned int NUMBER_OF_CENTROIDS >
class KMeansStandardV1Comparison1
{
public:

	typedef Algorithm::KMeansStandardV1_Util<OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS, NUMBER_OF_CENTROIDS>
		TSupportedKMeansStandardV1_Util;

	static typename TSupportedKMeansStandardV1_Util::TConstSpAlgorithmData getAlgorithmData()
	{
		static typename TSupportedKMeansStandardV1_Util::TConstSpAlgorithmData returned=
			__GenerateAlgorithmData::generate();
		return returned;
	}

	class NonConcurrent: public Test
	{
	public:
		typedef Algorithm::KMeansStandardV1NonConcurrent<OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS, NUMBER_OF_CENTROIDS> 
			TAlgorithm;
		typename TAlgorithm::SupportedKMeansStandardV1_Util::TSpAlgorithmData algorithmData;

		NonConcurrent():Test("KMeansStandardV1Comparison1::NonConcurrent")
		{
			algorithmData.reset(new TAlgorithm::SupportedKMeansStandardV1_Util::TAlgorithmData);
			*algorithmData=*getAlgorithmData();
		};

		void run()
		{
			TAlgorithm::algorithm(algorithmData);
		}
	};

	class ConcurrentV1: public Test
	{
	public:
		typedef Algorithm::KMeansStandardV1ConcurrentV1<OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS, NUMBER_OF_CENTROIDS>  
			TAlgorithm;
		typedef Algorithm::KMeansStandardV1NonConcurrent<OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS, NUMBER_OF_CENTROIDS>  
			TAlgorithmDebuging;

		typename TAlgorithm::SupportedKMeansStandardV1_Util::TSpAlgorithmData algorithmData;
		typename TAlgorithmDebuging::SupportedKMeansStandardV1_Util::TSpAlgorithmData algorithmDataDebuging;


		ConcurrentV1():Test("KMeansStandardV1Comparison1::ConcurrentV1")
		{

			algorithmData.reset(new TAlgorithm::SupportedKMeansStandardV1_Util::TAlgorithmData);
			*algorithmData=*getAlgorithmData();

			Logger::TurnOffLogger turnOffLogger;

			algorithmDataDebuging.reset(new TAlgorithm::SupportedKMeansStandardV1_Util::TAlgorithmData);
			*algorithmDataDebuging=*algorithmData;
			TAlgorithmDebuging::algorithm(algorithmDataDebuging);
		};

		void run()
		{
			TAlgorithm::algorithm(algorithmData);

			if(!(algorithmData->currentCentroids==algorithmDataDebuging->currentCentroids))
			{
				Logger::getOStream() << std::endl<<"Warning: invalid output " ;
				throw GlobalException("Invalid output");
			}

		}


	};

	class ConcurrentV2: public Test
	{
	public:
		typedef Algorithm::KMeansStandardV1ConcurrentV2<OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS, NUMBER_OF_CENTROIDS>  
			TAlgorithm;
		typedef Algorithm::KMeansStandardV1NonConcurrent<OBSERVATION_VECTOR_SIZE, NUMBER_OF_OBSERVATIONS, NUMBER_OF_CENTROIDS>  
			TAlgorithmDebuging;

		typename TAlgorithm::SupportedKMeansStandardV1_Util::TSpAlgorithmData algorithmData;
		typename TAlgorithmDebuging::SupportedKMeansStandardV1_Util::TSpAlgorithmData algorithmDataDebuging;


		ConcurrentV2():Test("KMeansStandardV1Comparison1::ConcurrentV2")
		{

			algorithmData.reset(new TAlgorithm::SupportedKMeansStandardV1_Util::TAlgorithmData);
			*algorithmData=*getAlgorithmData();

			Logger::TurnOffLogger turnOffLogger;

			algorithmDataDebuging.reset(new TAlgorithm::SupportedKMeansStandardV1_Util::TAlgorithmData);
			*algorithmDataDebuging=*algorithmData;
			TAlgorithmDebuging::algorithm(algorithmDataDebuging);
		};

		void run()
		{
			TAlgorithm::algorithm(algorithmData);

			if(!(algorithmData->currentCentroids==algorithmDataDebuging->currentCentroids))
			{
				Logger::getOStream() << std::endl<<"Warning: invalid output " ;
				throw GlobalException("Invalid output");
			}

		}


	};

};

}// namespace Tests

//_____________________________________________________________________________
//TMP TESTS
//_____________________________________________________________________________
namespace Tests
{

}// namespace Tests